package com.jiangruanjavaproject.address;

import com.jiangruanjavaproject.utils.Base58;
import com.jiangruanjavaproject.utils.Hash;

import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;
import java.util.Arrays;
import java.util.Base64;

/**
 * @author:wanfeng
 * @desc:该方法用于生成一个随机的EC算法的密钥对,并返回该密钥
 * @datetime:2021/12/24 9:02
 */
public class BitCoinAddress {

    private KeyPair generateKey(){
        //秘钥对生成器
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
           //parameter:参数
            //json-rpc:params
            //spec:specified 明确的,指定的 special 特别的
            ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
            generator.initialize(spec);//initialize 初始化 init
            generator.generateKeyPair();
            return generator.generateKeyPair();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return null;
    }
    /*
    * 该方法用于推荐生成原始格式的比特币的地址,并返回地址字符串
    * 随机的密钥对信息
    * 生成的比特币地址
    * */
     public String generateAddress(KeyPair keyPair){
         // TODO: 2021/12/24 推导原始格式地址
         //publicKey:公钥密码学的公钥
         ECPublicKey publicKey =(ECPublicKey) keyPair.getPublic();
        //原始格式公钥 :04+x坐标(32)+y坐标(32)
         byte[] pubKey = toUnCompressedPub(publicKey);
         byte[] sha256 = Hash.SHA256(pubKey);
         byte[] pubhash = Hash.encodeRIPEMD160(sha256);
         //界面添加版本号
         byte[] version = new byte[1];
         version[0]=0x00;
         byte[] ver_pubhash=new byte[version.length+pubhash.length];
         System.arraycopy(version,0,ver_pubhash,0,version.length);
        System.arraycopy(pubhash,0,ver_pubhash,version.length,pubhash.length);
        //对版本号_公钥哈希的序列进行双哈希,取前1个字节
         byte[] hash1 = Hash.SHA256(ver_pubhash);
         byte[] hash2 = Hash.SHA256(hash1);
         byte[] check = new byte[4];

         System.arraycopy(hash2,0,check,0,check.length);
         //将check 拼接var_pubhash后面,组成新的序列
         byte[] ver_pubhash_check = new byte[ver_pubhash.length+check.length];
         System.arraycopy(ver_pubhash,0,ver_pubhash_check,0,ver_pubhash.length);
         System.arraycopy(check,0,ver_pubhash_check,ver_pubhash.length,check.length);
         //base58编码
         return Base58.encode(ver_pubhash_check);

//        ECPoint point = publicKey.getW();
//         byte[] xBytes=  point.getAffineX().toByteArray();
//         byte[] yBytes=  point.getAffineY().toByteArray();
           //对公钥进行hash计算
         //原始格式公钥+x坐标(32字节)+y坐标(32字节)

        // return null;

     }

    /**
     * 该方法用于拼接得到非压缩格式(原始格式)的公钥,并返回原始公钥
     * @return原始格式公钥
     *///publicKey

     public static byte[] toUnCompressedPub(ECPublicKey publicKey){
         ECPoint point = publicKey.getW();
         byte[] xBytes=  point.getAffineX().toByteArray();
         byte[] yBytes=  point.getAffineY().toByteArray();
         //数组拷贝
         //原始格式结构 : 04(1)+x坐标(32)+y坐标(32)
         byte[] pubKey = new byte[1+2*32];
         pubKey[0] =04;
         //判断x坐标
         if (xBytes.length ==32){
             System.arraycopy(xBytes,0,pubKey,1,xBytes.length);
         }else if (xBytes.length>32){
             System.arraycopy(xBytes,1,pubKey,1,32);
         }

         //y坐标
         if (yBytes.length == 32){
             System.arraycopy(yBytes,0,pubKey,33,yBytes.length);

         }else  if (yBytes.length>32){
             System.arraycopy(yBytes,1,pubKey,33,32);
         }

         return pubKey;
     }
    /**
     * 生成以比特币地址,并返回
     * @return返回生成的比特币
     */
     public  String newAddress(){
         KeyPair keyPair =generateKey();
         return generateAddress(keyPair);
     }
    /**
     *该方法用于比特币地址字符串是否符合规范,并返回结果
     * @param address 要校验的比特币地址
     * @return 是否符合规范
     */
    public boolean validataAddress(String address){
        if ("".equals(address) || address == null){
            return  false;
        }
        byte [] ver_pubhash_check =Base58.decode(address);
       if (ver_pubhash_check.length<4){
           return  false;
       }

        //截取后四个字符,作为待验证的校验位
        byte[] check =new  byte[4];
        System.arraycopy(ver_pubhash_check,ver_pubhash_check.length-4,check,0,check.length);
        byte[]ver_pubhash =new  byte[ver_pubhash_check.length-4];
        System.arraycopy(ver_pubhash_check,0,ver_pubhash,0,ver_pubhash.length);

        //双hash
        byte[] hash1 = Hash.SHA256(ver_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);
        byte[] check_sum = new byte[4];
        System.arraycopy(hash2,0,check_sum,0,check_sum.length);

        return   Arrays.equals(check,check_sum);


    }

//临时测试使用
    public static void main(String[] args) {
        BitCoinAddress address = new BitCoinAddress();
        String str = address.newAddress();
        System.out.println("生成的地址"+ str);
        boolean result = address.validataAddress(str);
        System.out.println(result);
     }

}
